# -*- coding:utf-8 -*- 

from cn.pigersing.PyShare.Event import PyShareEventHandlerContainer, post_event
from cn.pigersing.PyShare.utils import LogPrint
from cn.pigersing.PyShare.utils.Xml2Obj import Element, Xml2Obj
from cn.pigersing.jsonrpc.jsonrpclib import HttpServerProxy20
import hashlib
import hmac
import socket
import threading


logger = LogPrint.get_logger('Session')
# don't display the debug information
#logger.setLevel(20)


class SessionError(Exception):pass
class SessionAlreadyExists(SessionError):pass
class NoThatSession(SessionError):pass


class Session(Element, PyShareEventHandlerContainer):
    
    def __init__(self, id="", url='http://localhost'):
        Element.__init__(self, 'Session')
        PyShareEventHandlerContainer.__init__(self)
        
        if not url.lower().startswith('http'):
            raise ValueError, 'Invalid URL format'
        
        self.setAttribute('id', id.lower())
        self.url = url
        self.id = id
        self.nickname = socket.gethostname()
        self.__private_key = ''
        self.__crt_key = ''
        #
        self._data_dict = {}
        self.__lock = threading.Lock()
        
        
    def url(): #@NoSelf
        def fget(self):
            return self.getAttribute('url')
        
        def fset(self, value):
            self.setAttribute('url', value)
            # set server proxy
            if value != "" :
                self.remote_server = HttpServerProxy20(value)
            else:
                self.remote_server = None
        
        return locals()
       
    url = property(**url())


    def id(): #@NoSelf
        def fget(self):
            return self.getAttribute('id')
        
        def fset(self, value):
            self.setAttribute('id', value.lower())

        return locals()
       
    id = property(**id())
    
    
    def nickname(): #@NoSelf
        doc = """nickname of current session""" #@UnusedVariable
       
        def fget(self):
            name = self.getAttribute('nickname')
            return name
        
        def fset(self, value):
            self.setAttribute('nickname', value)
           
        return locals()
       
    nickname = property(**nickname())
    
    
    def nickname_utf8(self):
        ''' Get the nickname of session encoded in UTF-8'''
        return self._attributes['nickname']
        
        
    def set_crt_key(self, private_key, public_key):
        self.__private_key = private_key
        self.__crt_key = self.__make_digest(public_key)
    
    
    def verify(self, key):
        if self.__crt_key == self.__make_digest(key) :
            return True
        
        return False
    
    
    def post_event(self, evt, directly = False):
        ''' notify the listeners to handle event send by current session'''
        if directly :
            for handler in self._evt_handlers :
                if handler.thread_safe :
                    handler.handle(evt)
        else :
            for handler in self._evt_handlers :
                post_event(evt, handler)
    
    
    def __getitem__(self, name):
        try :
            self.__lock.acquire()
            return self._data_dict[name.lower()]
        except KeyError :
            return None
        finally :
            self.__lock.release()
        
        
    def __setitem__(self, name, value) :
        try :
            self.__lock.acquire()
            self._data_dict[name.lower()] = value
        finally :
            self.__lock.release()
    
    
    def __delitem__(self, name):
        try :
            self.__lock.acquire()
            self._data_dict.__delitem__(name)
        except:pass
        finally :
            self.__lock.release()
        
        
    def __make_digest(self, key):
        '''Return a digest for the message.'''
        return hmac.new(self.__private_key, key, hashlib.sha1).hexdigest()
    
    
    @staticmethod
    def from_xml_string(src):
        element = element = Element.from_xml_string(src)
        s = Session(element.getAttribute('id'),
                       element.getAttribute('url'))
        s.nickname = element.getAttribute('nickname')
        return s
    
        
class SessionManager():
    
    def __init__(self):
        
        self.__sessions = {}
        self.__lock = threading.Lock()
        
    
    def add_session(self, session):
        
        id = session.id
        # safe guard
        self.__lock.acquire()
        if self.__sessions.has_key(id) :
            self.__lock.release()
            raise SessionAlreadyExists, id
        
        
        try:
            self.__sessions[id] = session
        finally:
            self.__lock.release()
        
    
    def get_session(self, key):
        
        if isinstance(key, Session) :
            id = key.id
        else:
            id = key
        
        self.__lock.acquire()   
        try:
            return self.__sessions[id]
        except KeyError:
            return None
        finally :
            self.__lock.release()
        
        
    def remove_session(self, val):
        
        if isinstance(val, Session) :
            id = val.id
        else:
            id = val
        
        # safe guard
        self.__lock.acquire()
        try:
            del self.__sessions[id]
        finally:
            self.__lock.release()
            
    
    def removeall_session(self):
        self.__sessions = {}
            
    
    def is_contained(self, val):
        
        if isinstance(val, Session) :
            id = val.id
        else:
            id = val
        
        return self.__sessions.has_key(id)
    
        
    def to_list(self):
        
        self.__lock.acquire()
        lst = [ x for x in self.__sessions.values() if x != self ]
        self.__lock.release()
        
        return lst
    
    
    @property
    def count(self): return len(self.__sessions)


#------------------------------------------------------------------------------ 
# test code
#------------------------------------------------------------------------------ 


if __name__ == '__main__' :
    
    s = Session('112033', 'http://localhost:8011')
    print s.to_xml()
    print s
    print 'id: ', s.id
    print 'url: ', s.url
    
    sm = SessionManager()
    
    sm.add_session(s)
    s1 = Session('112032', 'http://localhost:8011')
    sm.add_session(s1)
    
    print sm.to_list()
    
    try:
        sm.add_session(s)
    except SessionAlreadyExists, e:
        print e
    
    print sm.get_session('112033')
        
    sm.remove_session(s)
    logger.debug('deleted')
    
    print sm.count, sm.to_list()
    
    print Session.from_xml_string(s.to_xml())
    
    print s.nickname
    s.nickname = 'ant-man'
    print s.nickname
    s.set_crt_key('1111', '2222')
    print s.verify('2222')
    print s.verify('3333')